#include "ring_queue.hpp"
#include <cassert>
#include <iostream>
#ifdef _WIN32
    #include <windows.h>
#endif // _WIN32

class RingQueueTest
{
public:
    void displayin() const
    {
        std::cout << "in value =" << this->value << '\n';
    }

    void displayout() const
    {
        std::cout << "out value =" << this->value << '\n';
    }

    int value;
};

RingQueue<RingQueueTest> ring_queue(0);

enum ProcessTimes
{
    SINGLE_PRODUCE_TIMES = 10000000,
    SINGLE_CONSUME_TIMES = SINGLE_PRODUCE_TIMES,
    MULTI_PRODUCE_TIMES = SINGLE_PRODUCE_TIMES / 2,
    MULTI_CONSUME_TIMES = MULTI_PRODUCE_TIMES
};

void SingleProduce()
{
    uint64_t i = 0;
    RingQueueTest obj1[5];
    obj1[0].value = 1;
    obj1[1].value = 2;
    obj1[2].value = 3;
    obj1[3].value = 4;
    obj1[4].value = 5;
    while (i < ProcessTimes::SINGLE_PRODUCE_TIMES)
    {
        if (ring_queue.SingleProducerEnQueue(obj1, 5))
        {
            ++i;
        }
    }
}

void SingleConsume()
{
    uint64_t i = 0;
    RingQueueTest obj[5];
    while (i < ProcessTimes::SINGLE_CONSUME_TIMES)
    {
        if (ring_queue.SingleConsumerDeQueue(obj, 5))
        {
            assert(obj[0].value == 1);
            assert(obj[1].value == 2);
            assert(obj[2].value == 3);
            assert(obj[3].value == 4);
            assert(obj[4].value == 5);
            ++i;
        }
    }
}

void MultiProduce()
{
    uint64_t i = 0;
    RingQueueTest obj1[5];
    obj1[0].value = 1;
    obj1[1].value = 2;
    obj1[2].value = 3;
    obj1[3].value = 4;
    obj1[4].value = 5;
    while (i < ProcessTimes::MULTI_PRODUCE_TIMES)
    {
        if (ring_queue.MultiProducerEnQueue(obj1, 5))
        {
            ++i;
        }
    }
}

void MultiConsume()
{
    uint64_t i = 0;
    RingQueueTest obj[5];
    while (i < ProcessTimes::MULTI_CONSUME_TIMES)
    {
        if (ring_queue.MultiConsumerDeQueue(obj, 5))
        {
            assert(obj[0].value == 1);
            assert(obj[1].value == 2);
            assert(obj[2].value == 3);
            assert(obj[3].value == 4);
            assert(obj[4].value == 5);
            ++i;
        }
    }
}

void Test1()
{
    // 1.单生产者，单消费者
    std::thread producer(SingleProduce);
    std::thread consumer(SingleConsume);
    producer.join();
    consumer.join();
}

void Test2()
{
    // 2.单生产者，多消费者
    std::thread producer(SingleProduce);
    std::thread consumer1(MultiConsume);
    std::thread consumer2(MultiConsume);
    producer.join();
    consumer1.join();
    consumer2.join();
}

void Test3()
{
    // 3.多生产者，多消费者
    std::thread producer1(MultiProduce);
    std::thread consumer1(MultiConsume);
    std::thread producer2(MultiProduce);
    std::thread consumer2(MultiConsume);
    producer1.join();
    consumer1.join();
    producer2.join();
    consumer2.join();
}

void Test4()
{
    // 4.多生产者，单消费者
    std::thread producer1(MultiProduce);
    std::thread producer2(MultiProduce);
    std::thread consumer(SingleConsume);
    producer1.join();
    producer2.join();
    consumer.join();
}

int main()
{
#ifdef _WIN32
    SetConsoleCP(65001);
    SetConsoleOutputCP(65001);
#endif // _WIN32
    Test1();
    Test2();
    Test3();
    Test4();
    return 0;
}